#include "iotgo_service.h"
#include "iotgo_memory_hooks.h"
#include "iotgo.h"
#include "cJSON.h"
#include "data_pool.h"
#include "custom_data_type.h"

#include <stdio.h>       /* for printf */

#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>

#define SUCCEED 0
#define FAIL   -1

#define DATA_PASS_POOL_LEN 2048

static uint32_t connect_thread_num = 0;
static uint32_t pair_mode_over_time = 600;
static DataPool *data_pass_pool = NULL;


static pthread_t iotgoRuntimeThread;
static pthread_t iotgoRuntimeMonitorThread;

static int32_t startIotgoThreads(void);
static void storePassData(uint8_t *sequence,uint8_t *params);
static void applyUpdateFromServer(uint8_t *sequence,uint8_t *params);
static void applyUpgradeFromServer(uint8_t *sequence,uint8_t *read_buf);
static void applyFisrtUpdate(void);

int32_t iotgoConnect(void)
{
    int32_t ret;
    if( connect_thread_num != 0)
    {
	printf("[%s][warn] Iotgo services has been running!\n",__FUNCTION__);
	return ERROR_MUTIRUN;
    }

    ret = startIotgoThreads();

    if(ret != SUCCEED)
    {
	printf("[%s][error] Fail to create iotgo services.\n",__FUNCTION__);
	return ERROR_CREATE_THREAD;
    }
    return SUCCEED;
}


int32_t configWithApp(uint8_t overtime)
{
    int32_t ret = 0;
    if( connect_thread_num == 0)
    {
        ret = startIotgoThreads();
	if(ret != SUCCEED)
	{
	    printf("[%s][error] Fail to create iotgo services.\n",__FUNCTION__);
	    return ERROR_CREATE_THREAD;
	}
    }

    pair_mode_over_time = overtime * 10;
    ret = iotgoPairWithAppStart();

    if(ret == IOTGO_ERROR_NONE)
    {
	return SUCCEED;
    }

    return FAIL;
}

int32_t iotgoRead(uint32_t fd, void *buf, size_t nbytes)
{
    int8_t iotgo_state = IOTGO_IDLE;
    int32_t count = 0;

    iotgo_state = iotgoGetState();
    if(iotgo_state != IOTGO_REGISTER_IS_READY)
    {
	printf("[%s][warn]iotgo connection is not ready\n",__FUNCTION__);
	return ERROR_CONNECTION_NOT_READY;
    }

    count = readFromDataPool(data_pass_pool,buf,nbytes);
    return count;
}

int32_t iotgoWrite(uint32_t fd, void *buf, size_t nbytes)
{
    int8_t iotgo_state = IOTGO_IDLE;

    cJSON *cjson_param = NULL;
    cJSON *cjson_pass_data = NULL;
    int8_t *param = NULL;
    uint8_t *tmp = NULL;
    
    iotgo_state = iotgoGetState();
    if(iotgo_state != IOTGO_REGISTER_IS_READY)
    {
	printf("[%s][warn]iotgo connection is not ready\n",__FUNCTION__);
	return ERROR_CONNECTION_NOT_READY;
    }

    tmp = malloc(nbytes+1);

    if(tmp)
    {
	memcpy(tmp,buf,nbytes);
	tmp[nbytes] = '\0';

	cjson_param = cJSON_CreateObject();
	if(cjson_param)
	{
	    cJSON_AddItemToObject(cjson_param,"data",cJSON_CreateString(tmp));
	    param = (int8_t *)cJSON_PrintUnformatted(cjson_param);
	    iotgoWriteUpdateToServer(param);
	    if(param)
	    {
		pFree(param);
	    }
	    if(cjson_param)
	    {
		cJSON_Delete(cjson_param);
	    }
	    free(tmp);

	    return nbytes;
	}
	free(tmp);
    }

    return FAIL;
}

int32_t iotgoUpdateP2Ppassword(uint8_t *mechineID, uint8_t *p2pID, uint8_t *password)
{
    int32_t i = 0;
    int8_t iotgo_state = IOTGO_IDLE;
    uint8_t tmp_machineID[32] = {0};
    uint8_t tmp_p2pID[32] = {0};
    uint8_t tmp_password[32] = {0};

    cJSON *cjson_params = NULL;
    int8_t *param = NULL;

    iotgo_state = iotgoGetState();
    if(iotgo_state != IOTGO_REGISTER_IS_READY)
    {
	printf("[%s][warn]iotgo connection is not ready\n",__FUNCTION__);
	return ERROR_CONNECTION_NOT_READY;
    }

    for(i = 0; i < 31; i++)
    {
	tmp_machineID[i] = *(mechineID + i);
	tmp_p2pID[i] = *(p2pID + i);
	tmp_password[i] = *(password +i);
    }
    tmp_machineID[31] = '\0';
    tmp_p2pID[31] = '\0';
    tmp_password[31] = '\0';

    cjson_params = cJSON_CreateObject();
    if(cjson_params)
    {
	cJSON_AddItemToObject(cjson_params ,"machine_id" ,cJSON_CreateString(tmp_machineID));
	cJSON_AddItemToObject(cjson_params ,"p2p_id" ,cJSON_CreateString(tmp_p2pID));
	cJSON_AddItemToObject(cjson_params ,"p2p_password" ,cJSON_CreateString(tmp_password));
	param = (int8_t *)cJSON_PrintUnformatted(cjson_params);
	iotgoWriteUpdateToServer(param);
        if(param)
        {
            pFree(param);
        }
        if(cjson_params)
        {
            cJSON_Delete(cjson_params);
	}
	return SUCCEED;
    }
    return FAIL;
}

int8_t iotgoUpdateWifiRssi(uint8_t rssi)
{
    int8_t iotgo_state = IOTGO_IDLE;

    cJSON *cjson_params = NULL;
    int8_t *param = NULL;

    iotgo_state = iotgoGetState();
    if(iotgo_state != IOTGO_REGISTER_IS_READY)
    {
	printf("[%s][warn]iotgo connection is not ready\n",__FUNCTION__);
	return ERROR_CONNECTION_NOT_READY;
    }

    cjson_params = cJSON_CreateObject();
    if(cjson_params)
    {
	cJSON_AddItemToObject(cjson_params ,"rssi" ,cJSON_CreateNumber(rssi));
	param = (int8_t *)cJSON_PrintUnformatted(cjson_params);
	iotgoWriteUpdateToServer(param);
        if(param)
        {
            pFree(param);
        }
        if(cjson_params)
        {
            cJSON_Delete(cjson_params);
	}
	return SUCCEED;
    }
    return FAIL;
}

int8_t iotgoUpdateStatusLed(uint8_t led_status)
{
    int8_t iotgo_state = IOTGO_IDLE;

    cJSON *cjson_params = NULL;
    int8_t *param = NULL;

    iotgo_state = iotgoGetState();
    if(iotgo_state != IOTGO_REGISTER_IS_READY)
    {
	printf("[%s][warn]iotgo connection is not ready\n",__FUNCTION__);
	return ERROR_CONNECTION_NOT_READY;
    }

    cjson_params = cJSON_CreateObject();
    if(cjson_params)
    {
	cJSON_AddItemToObject(cjson_params ,"status_led" ,cJSON_CreateNumber(led_status));
	param = (int8_t *)cJSON_PrintUnformatted(cjson_params);
	iotgoWriteUpdateToServer(param);
        if(param)
        {
            pFree(param);
        }
        if(cjson_params)
        {
            cJSON_Delete(cjson_params);
	}
	return SUCCEED;
    }
    return FAIL;
}

int8_t iotgoUpdateOtaDone(uint8_t *sequence)
{
    int8_t iotgo_state = IOTGO_IDLE;

    iotgo_state = iotgoGetState();
    if(iotgo_state != IOTGO_REGISTER_IS_READY)
    {
	printf("[%s][warn]iotgo connection is not ready\n",__FUNCTION__);
	return ERROR_CONNECTION_NOT_READY;
    }

    iotgoWriteErrorNumToServer(0,sequence);
    return 0;
}

int8_t iotgoUpdateStorageInfo(void *pstruct)
{
    int8_t iotgo_state = IOTGO_IDLE;
    STORAGE_INFO *pStorage = (STORAGE_INFO *)pstruct;

    cJSON *cjson_params = NULL;
    int8_t *param = NULL;

    iotgo_state = iotgoGetState();
    if(iotgo_state != IOTGO_REGISTER_IS_READY)
    {
	printf("[%s][warn]iotgo connection is not ready\n",__FUNCTION__);
	return ERROR_CONNECTION_NOT_READY;
    }

    cjson_params = cJSON_CreateObject();
    if(cjson_params)
    {
	cJSON_AddItemToObject(cjson_params ,"storage_total" ,cJSON_CreateNumber(pStorage->total));
	cJSON_AddItemToObject(cjson_params ,"storage_remain" ,cJSON_CreateNumber(pStorage->remain));
	param = (int8_t *)cJSON_PrintUnformatted(cjson_params);
	iotgoWriteUpdateToServer(param);
        if(param)
        {
            pFree(param);
        }
        if(cjson_params)
        {
            cJSON_Delete(cjson_params);
	}
	return SUCCEED;
    }
    return FAIL;
}

int8_t iotgoUpdateMotionAlert(void *pstruct)
{
    int8_t iotgo_state = IOTGO_IDLE;
    ALERT_INFO *pAlert = (ALERT_INFO *)pstruct;

    cJSON *cjson_params = NULL;
    int8_t *param = NULL;

    iotgo_state = iotgoGetState();
    if(iotgo_state != IOTGO_REGISTER_IS_READY)
    {
	printf("[%s][warn]iotgo connection is not ready\n",__FUNCTION__);
	return ERROR_CONNECTION_NOT_READY;
    }

    cjson_params = cJSON_CreateObject();
    if(cjson_params)
    {
	cJSON_AddItemToObject(cjson_params ,"alert_num" ,cJSON_CreateNumber(pAlert->num));
	cJSON_AddItemToObject(cjson_params ,"alert_time" ,cJSON_CreateNumber(pAlert->time));
	cJSON_AddItemToObject(cjson_params ,"alert_type" ,cJSON_CreateNumber(pAlert->type));
	param = (int8_t *)cJSON_PrintUnformatted(cjson_params);
	iotgoWriteUpdateToServer(param);
        if(param)
        {
            pFree(param);
        }
        if(cjson_params)
        {
            cJSON_Delete(cjson_params);
	}
	return SUCCEED;
    }
    return FAIL;
}

static int parseTimeMessage(uint8_t *date, struct tm *result)
{
    /*date should be like: "2016-03029T06:56:08.514Z"*/
    uint8_t s_year[5] = {0};
    uint8_t s_mon[3] = {0};
    uint8_t s_day[3] = {0};
    uint8_t s_hour[3] = {0};
    uint8_t s_minute[3] = {0};
    uint8_t s_second[3] = {0};
    
    uint8_t count = 0;
    
    if(*(date + 4)  == '-' &&
       *(date + 7)  == '-' &&
       *(date + 10) == 'T' &&
       *(date + 13) == ':' &&
       *(date + 16) == ':' &&
       *(date + 19) == '.' &&
       *(date + 23) == 'Z')  
    {
        /*right date format*/
        memcpy(s_year,date,4);
        memcpy(s_mon,date+5,2);
        memcpy(s_day,date+8,2);
        memcpy(s_hour,date+11,2);
        memcpy(s_minute,date+14,2);
        memcpy(s_second,date+17,2);
        
        result->tm_year = atoi(s_year);
        result->tm_mon  = atoi(s_mon);
        result->tm_mday = atoi(s_day);
        result->tm_hour = atoi(s_hour);
        result->tm_min  = atoi(s_minute);
        result->tm_sec  = atoi(s_second);
        
        return 0;
    }
    return -1;
}


int8_t updateDateFromServer(uint8_t *pGMTmessage)
{
    struct tm tmp;
    time_t seconds;
    struct tm *p_time;
    
    
    int32_t ret = -1;
    struct tm timeinfo;
    struct timeval tv;

    ret = parseTimeMessage(pGMTmessage, &tmp);
    if(ret == 0)
    {
        tmp.tm_year -= 1900;
        tmp.tm_mon -= 1;
	tmp.tm_hour += 8;

        seconds = mktime(&tmp);

	tv.tv_sec  = seconds;
	tv.tv_usec = 0;
	ret = settimeofday(&tv,NULL);
	printf("[%s] settimeofday return is [%d]\n",__FUNCTION__);
    }
    return ret;
}

void *iotgoRuntimeService(void *arg)
{
    int8_t error = IOTGO_ERROR_NONE;
    int8_t data_type = IOTGO_DATA_TYPE_NONE;
    int8_t iotgo_state = IOTGO_IDLE;
    
    uint8_t sequence[14] = {0};
    int8_t read_buf[2048] = {0};
    int32_t ret = -1;
    uint8_t first_update_is_not_done = 1;
    uint8_t flag_update_time_from_server = 0;

    struct sched_param sched;
    int priority;

    priority = sched_get_priority_max(SCHED_RR) - 1;
    sched.sched_priority = priority;
    if(pthread_setschedparam(iotgoRuntimeThread,SCHED_RR,&sched) != 0)
    {
	printf("[%s] pthread_setschedparam failed\n",__FUNCTION__);
    }
    else
    {
	printf("[%s] iotgoRuntimeThread : SCHED_RR priority [%d]\n",__FUNCTION__,priority);
    }

    printf("[%s] service starts\n",__FUNCTION__);
    while(1)
    {
	iotgoDataServiceRuntime();
        iotgo_state = iotgoGetState();
        if(iotgo_state == IOTGO_REGISTER_IS_READY)
        {
            ret = iotgoReadByDataType(IOTGO_DATA_TYPE_UPDATE,sequence,read_buf);
            if(ret == 0)
            {
                printf("[%s]get update\n",__FUNCTION__);
                printf("[%s]params is %s\n",__FUNCTION__,read_buf);
		storePassData(sequence,read_buf);
		applyUpdateFromServer(sequence,read_buf);
            }

            /* check the upgrade command*/
            ret = iotgoReadByDataType(IOTGO_DATA_TYPE_UPGRADE,sequence,read_buf);
            if(ret == 0)
            {
                printf("[%s]get upgrade query",__FUNCTION__);
                printf("[%s]data is %s\n",__FUNCTION__,read_buf);
		applyUpgradeFromServer(sequence,read_buf);
            }

            /* check the date query return*/
            ret = iotgoReadByDataType(IOTGO_DATA_TYPE_DATE,sequence,read_buf);
            if(ret == 0)
            {
                printf("[%s]get date\n",__FUNCTION__);
                printf("[%s]date is \n%s\n",__FUNCTION__,read_buf);
		updateDateFromServer(read_buf);
            }

	    if(flag_update_time_from_server == 1)
	    {
		flag_update_time_from_server = 0;
		printf("[%s]query time from server\n",__FUNCTION__);
		iotgoWriteDateQueryToServer();
	    }
            
            if(first_update_is_not_done)
            {
                first_update_is_not_done = 0;
		applyFisrtUpdate();
		flag_update_time_from_server = 1;
            }
	    
            memset(read_buf,0,2048);
        }

    }
}

void *iotgoRuntimeMonitor(void *arg)
{
    int32_t monitor_pair_state_count = 0;
    int32_t monitor_iotgo_state = 0;
    int8_t ret = 0;
    int32_t time_count = 0;

    struct sched_param sched;
    int priority;

    priority = sched_get_priority_max(SCHED_RR) - 2;
    sched.sched_priority = priority;
    if(pthread_setschedparam(iotgoRuntimeMonitorThread,SCHED_RR,&sched) != 0)
    {
	printf("[%s] pthread_setschedparam failed\n",__FUNCTION__);
    }
    else
    {
	printf("[%s] iotgoRuntimeMonitorThread : SCHED_RR priority [%d]\n",__FUNCTION__,priority);
    }

    printf("[%s] monitor starts\n",__FUNCTION__);
    while(1)
    {
        monitor_iotgo_state = iotgoGetState();
        switch(monitor_iotgo_state)
        {
	case IOTGO_PAIR_WITH_APP:
	    monitor_pair_state_count++;
	    if(monitor_pair_state_count == pair_mode_over_time && pair_mode_over_time != 0)
	    {
		iotgoPairWithAppStop();
		monitor_pair_state_count = 0;
	    }
	    if(monitor_pair_state_count & 0x01 == 0x01)
	    {
		ret = getStatusLed();
		if(ret == 0)
		{
		    setStatusLed(1);
		}
		else if(ret == 1)
		{
		    setStatusLed(0);
		}
	    }
	    break;
	case IOTGO_IDLE:
	case IOTGO_AP_IS_CONNECTED:
	case IOTGO_DSERVER_IS_CONNECTED:
	case IOTGO_LSERVER_IS_CONNECTED:
	case IOTGO_REGISTER_IS_READY:
	case IOTGO_UPGRADE:
	default:
	    break;
        }

	time_count++;
	if(time_count == 100) // 1 minite 
	{
	    //iotgoWriteDateQueryToServer();
	    time_count = 0;
	}
        systemDelayMs(100);
    }
}

static int32_t startIotgoThreads(void)
{
    int32_t ret = 0;

    printf("[%s]create data pools\n",__FUNCTION__);
    data_pass_pool = createDataPool(DATA_PASS_POOL_LEN);
    if(data_pass_pool == NULL)
    {
	printf("[%s][error]fail to create data pool\n",__FUNCTION__);
	return ERROR_CREATE_DATA_POOL;
    }

    printf("[%s]create iotgo runtime service\n",__FUNCTION__);
    ret = pthread_create(&iotgoRuntimeThread,NULL,iotgoRuntimeService,NULL);
    if (ret != SUCCEED)
    {
	printf("[%s][error]create iotgoRuntimeThread failed\n",__FUNCTION__);
	connect_thread_num = 0;
	return ERROR_CREATE_THREAD;
    }

    printf("[%s]create iotgo runtime monitor service\n",__FUNCTION__);
    ret = pthread_create(&iotgoRuntimeMonitorThread,NULL,iotgoRuntimeMonitor,NULL);
    if (ret != SUCCEED)
    {
	printf("[%s][error] create iotgoRumtimeMonitorThread failed\n",__FUNCTION__);
	printf("[%s][action] cancel iotgo's services\n",__FUNCTION__);
	connect_thread_num = 0;
	pthread_cancel(iotgoRuntimeThread);
	pthread_join(iotgoRuntimeThread,NULL);
	return ERROR_CREATE_THREAD;
    }

    connect_thread_num = 1;

    return SUCCEED;
}

static void storePassData(uint8_t *sequence,uint8_t *params)
{
    cJSON *cjson_params = NULL;
    cJSON *cjson_pass_data = NULL;

    cjson_params = cJSON_Parse(params);
    if(cjson_params)
    {
        cjson_pass_data = cJSON_GetObjectItem(cjson_params,"data");
        if(cjson_pass_data)
        {
            printf("[%s]get data %s\n",__FUNCTION__,cjson_pass_data->valuestring);
            iotgoWriteErrorNumToServer(0,sequence);
	    writeToDataPool(data_pass_pool,
			    cjson_pass_data->valuestring,
			    strlen(cjson_pass_data->valuestring));
        }
        cJSON_Delete(cjson_params);
    }
}

static void updateCloudStoreParamFormServer(uint8_t *sequence, cJSON *root)
{
    CLOUD_STORE_PARAM cloud_param;
    uint8_t count = 0;
    cJSON *param_captureNumber = NULL;
    cJSON *param_lengthOfVideo = NULL;
    cJSON *param_uploadLimit = NULL;
    cJSON *param_storeType = NULL;
    cJSON *param_storeAppid = NULL;
    cJSON *param_storeAppSecret = NULL;
    cJSON *param_callbackUrl = NULL;
    cJSON *param_callbackHost = NULL;
    cJSON *param_callbackBody = NULL;
    cJSON *param_bucketName = NULL;
    cJSON *param_statusReportUrl = NULL;
    cJSON *param_persistentPipeline = NULL;
    cJSON *param_persistentOps = NULL;
    cJSON *param_persistentNotifyUrl = NULL;
    cJSON *param_deleteAfterDays = NULL;

    param_captureNumber = cJSON_GetObjectItem(root,"captureNumber");
    if(param_captureNumber)
    {
	cloud_param.captureNumber = param_captureNumber->valueint;
	count++;
    }
    param_lengthOfVideo = cJSON_GetObjectItem(root,"lengthOfVideo");
    if(param_lengthOfVideo)
    {
	cloud_param.lengthOfVideo = param_lengthOfVideo->valueint;
	count++;
    }
    param_uploadLimit = cJSON_GetObjectItem(root,"uploadLimit");
    if(param_uploadLimit)
    {
	cloud_param.uploadLimit = param_uploadLimit->valueint;
	count++;
    }
    param_storeType = cJSON_GetObjectItem(root,"storetype");
    if(param_storeType)
    {
	cloud_param.storeType = param_storeType->valueint;
	count++;
    }
    param_storeAppid = cJSON_GetObjectItem(root,"storeAppid");
    if(param_storeAppid)
    {
	strcpy((cloud_param.storeAppid),(param_storeAppid->valuestring));
	count++;
    }
    param_storeAppSecret = cJSON_GetObjectItem(root,"storeAppSecret");
    if(param_storeAppSecret)
    {
	strcpy((cloud_param.storeAppSecret),(param_storeAppSecret->valuestring));
	count++;
    }
    param_callbackUrl = cJSON_GetObjectItem(root,"callbackUrl");
    if(param_callbackUrl)
    {
	strcpy((cloud_param.callbackUrl),(param_callbackUrl->valuestring));
	count++;
    }
    param_callbackHost = cJSON_GetObjectItem(root,"callbackHost");
    if(param_callbackHost)
    {
	strcpy((cloud_param.callbackHost),(param_callbackHost->valuestring));
	count++;
    }
    param_callbackBody = cJSON_GetObjectItem(root,"callbackBody");
    if(param_callbackBody)
    {
	strcpy((cloud_param.callbackBody),(param_callbackBody->valuestring));
	count++;
    }    
    param_bucketName = cJSON_GetObjectItem(root,"bucketName");
    if(param_bucketName)
    {
	strcpy((cloud_param.bucketName),(param_bucketName->valuestring));
	count++;
    }   

    param_persistentPipeline = cJSON_GetObjectItem(root,"persistentPipeline");
    if(param_persistentPipeline)
    {
	strcpy((cloud_param.persistentPipeline),(param_persistentPipeline->valuestring));
	count++;
    }   

    param_persistentOps = cJSON_GetObjectItem(root,"persistentOps");
    if(param_persistentOps)
    {
	strcpy((cloud_param.persistentOps),(param_persistentOps->valuestring));
	count++;
    }   

    param_persistentNotifyUrl = cJSON_GetObjectItem(root,"persistentNotifyUrl");
    if(param_persistentNotifyUrl)
    {
	strcpy((cloud_param.persistentNotifyUrl),(param_persistentNotifyUrl->valuestring));
	count++;
    }   

    param_deleteAfterDays = cJSON_GetObjectItem(root,"deleteAfterDays");
    if(param_persistentPipeline)
    {
	cloud_param.deleteAfterDays = param_deleteAfterDays->valueint;
	count++;
    }   

    param_statusReportUrl = cJSON_GetObjectItem(root,"statusReportUrl");
    if(param_statusReportUrl)
    {
	storeCloudResultPostUrl(param_statusReportUrl->valuestring);
    }   


    if(count == 14)
    {
	printf("[%s] update cloud store set\n",__FUNCTION__);
	setCloudStoreParam(&cloud_param);
	iotgoWriteErrorNumToServer(0,sequence);
    }
    else if(count > 0)
    {
	printf("[%s] params are not enough\n",__FUNCTION__);
	iotgoWriteErrorNumToServer(404,sequence);
    }
}


static void updateP2PinfoFormServer(uint8_t *sequence, cJSON *root)
{
    P2P_INFO info;
    uint8_t count = 0;
    cJSON *p2p_serverName = NULL;
    cJSON *p2p_account = NULL;
    cJSON *p2p_license = NULL;

    p2p_serverName = cJSON_GetObjectItem(root,"p2pServerName");
    if(p2p_serverName)
    {
	strcpy((info.serverName),(p2p_serverName->valuestring));
	count++;
    }
    p2p_account = cJSON_GetObjectItem(root,"p2pAccout");
    if(p2p_account)
    {
	strcpy((info.account),(p2p_account->valuestring));
	count++;
    }
    p2p_license = cJSON_GetObjectItem(root,"p2pLicense");
    if(p2p_license)
    {
	strcpy((info.license),(p2p_license->valuestring));
	count++;
    }
    if(count == 3)
    {
	printf("[%s] update P2P info\n",__FUNCTION__);
	setP2Pinfo(&info);
	iotgoWriteErrorNumToServer(0,sequence);
    }
    else if(count > 0)
    {
	printf("[%s] params are not enough\n",__FUNCTION__);
	iotgoWriteErrorNumToServer(404,sequence);
    }
}

static void updateFlipinfoFormServer(uint8_t *sequence, cJSON *root)
{
    P2P_INFO info;
    uint8_t count = 0;
    cJSON *horiflip = NULL;
    cJSON *veriflip = NULL;
    int hori_flip = 0;
    int veri_flip = 0;

    char *tmp = NULL;

    horiflip = cJSON_GetObjectItem(root,"horiFlip");
    if(horiflip)
    {
	hori_flip = horiflip->valueint;
	count++;
    }
    veriflip = cJSON_GetObjectItem(root,"VeriFlip");
    if(veriflip)
    {
	veri_flip = veriflip->valueint;
	count++;
    }

    if(count == 2)
    {
	printf("[%s] update flip info\n",__FUNCTION__);
	ChangeFlipParam(hori_flip, veri_flip);
	iotgoWriteErrorNumToServer(0,sequence);
    }
    else if(count > 0)
    {
	printf("[%s] params are not enough\n",__FUNCTION__);
	iotgoWriteErrorNumToServer(404,sequence);
    }
}



static void applyUpdateFromServer(uint8_t *sequence,uint8_t *params)
{
    cJSON *cjson_params = NULL;
    cJSON *cjson_status_led = NULL;
    cJSON *cjson_status_camera = NULL;
    cJSON *cjson_motion_monitor = NULL;
    cJSON *cjson_motion_monitor_sensitivity = NULL;
    cJSON *cjson_cloud_store = NULL;
     
    cjson_params = cJSON_Parse(params);

    if(cjson_params)
    {
	cjson_status_led = cJSON_GetObjectItem(cjson_params,"status_led");
	if(cjson_status_led)
	{
	    printf("[%s] update status led\n set",__FUNCTION__);
	    setStatusLed(cjson_status_led->valueint);
	    iotgoWriteErrorNumToServer(0,sequence);
	}
	cjson_status_camera = cJSON_GetObjectItem(cjson_params,"status_camera");
	if(cjson_status_camera)
	{
	    printf("[%s] update camera status set\n",__FUNCTION__);
	    setCameraStatus(cjson_status_camera->valueint);
	    iotgoWriteErrorNumToServer(0,sequence);
	}
	cjson_motion_monitor = cJSON_GetObjectItem(cjson_params,"motion_monitor");
	if(cjson_motion_monitor)
	{
	    printf("[%s] update motion monitor set\n",__FUNCTION__);
	    setMotionMonitorStatus(cjson_motion_monitor->valueint);
	    iotgoWriteErrorNumToServer(0,sequence);
	}
	cjson_motion_monitor_sensitivity = cJSON_GetObjectItem(cjson_params,"motion_monitor_sensitivity");
	if(cjson_motion_monitor_sensitivity)
	{
	    printf("[%s] update motion monitor sensitivity\n",__FUNCTION__);
	    setMotionMonitorSensitivity(cjson_motion_monitor_sensitivity->valueint);
	    iotgoWriteErrorNumToServer(0,sequence);
	}
	cjson_cloud_store = cJSON_GetObjectItem(cjson_params,"cloud_store");
	if(cjson_cloud_store)
	{
	    printf("[%s] update cloud store set\n",__FUNCTION__);
	    setCloudStoreStatus(cjson_cloud_store->valueint);
	    iotgoWriteErrorNumToServer(0,sequence);
	}
	updateCloudStoreParamFormServer(sequence, cjson_params);
	updateP2PinfoFormServer(sequence, cjson_params);
	updateFlipinfoFormServer(sequence, cjson_params);
	cJSON_Delete(cjson_params);
    }

}


static int parseUpgradeMessage(unsigned char *params,uint8_t *url,uint8_t *digest)
{
    cJSON *cjson_params = NULL;
    cJSON *cjson_binList = NULL;
    cJSON *cjson_bin = NULL;
    cJSON *cjson_digest = NULL;
    cJSON *cjson_downloadUrl = NULL;
    cJSON *cjson_bin_name = NULL;
    unsigned char flag = 0;

    cjson_params = cJSON_Parse(params);

    if(cjson_params)
    {
	printf("[%s] params get\n",__FUNCTION__);
	cjson_binList = cJSON_GetObjectItem(cjson_params,"binList");
	if(cjson_binList)
	{
	    printf("[%s] cjson_binList get\n",__FUNCTION__);
	    cjson_bin = cJSON_GetArrayItem(cjson_binList,0);
	    if(cjson_bin)
	    {
		printf("[%s] cjson_bin get\n",__FUNCTION__);
		cjson_digest = cJSON_GetObjectItem(cjson_bin,"digest");
		if(cjson_digest)
		{
		    memcpy(digest,
			   cjson_digest->valuestring,
			   strlen(cjson_digest->valuestring));
		    printf("[%s] digest is[%s]\n",__FUNCTION__,
			   cjson_digest->valuestring);
		    flag++;
		}
		cjson_downloadUrl = cJSON_GetObjectItem(cjson_bin,"downloadUrl");
		if(cjson_downloadUrl)
		{
		    printf("[%s] downloadUrl is[%s]\n",__FUNCTION__,
			   cjson_downloadUrl->valuestring);
		    memcpy(url,
			   cjson_downloadUrl->valuestring,
			   strlen(cjson_downloadUrl->valuestring));
		    flag++;
		}
		cjson_bin_name = cJSON_GetObjectItem(cjson_bin,"name");
		if(cjson_bin_name)
		{
#if 0
		    memcpy(bin_name,
			   cjson_bin_name->valuestring,
			   strlen(cjson_bin_name->valuestring));

		    printf("[%s] name is[%s]\n",__FUNCTION__,bin_name);
#endif
		    flag++;
		}//cjson_bin_name
	    }//cjson_bin
	}//cjson_binList
	cJSON_Delete(cjson_params);
    }//cjson_params


    if(flag == 3)
    {
	return 0;
    }
    else 
    {
	return -1;
    }
}


static void applyUpgradeFromServer(uint8_t *sequence,uint8_t *read_buf)
{
    uint8_t origin_digest[65] = {0};
    uint8_t origin_url[125] = {0};
    uint8_t origin_sequence[14] = {0};
    int8_t ret = -1;

    memcpy(origin_sequence,sequence,strlen(sequence));
    ret = parseUpgradeMessage(read_buf,origin_url,origin_digest);
    if(ret == 0)
    {
	setOtaInfo(origin_url,origin_digest,origin_sequence);
    }
}

static void applyFisrtUpdate(void)
{
    cJSON *cjson_param = NULL;
    uint8_t *param = NULL;
    uint8_t rssi_number;
    uint8_t status_led;
    STATION_INFO station;
    STORAGE_INFO storage;
    uint8_t status_camera;
    uint8_t motion_monitor;
    uint8_t motion_monitor_sens;
    uint8_t cloud_store;

    rssi_number = getWifiRssi();
    status_led = getStatusLed();
    motion_monitor = getMotionMonitorStatus();
    motion_monitor_sens = getMotionMonitorSensitivity();
    status_camera = getCameraStatus();
    cloud_store = getCloudStoreStatus();
    getWifiInfo(&station);
    getStorageInfo(&storage);

    cjson_param = cJSON_CreateObject();
    if(cjson_param)
    {
	cJSON_AddItemToObject(cjson_param,"rssi",cJSON_CreateNumber(rssi_number));
	cJSON_AddItemToObject(cjson_param,"ip_add",cJSON_CreateString(station.ip_add));
	cJSON_AddItemToObject(cjson_param,"mac_add",cJSON_CreateString(station.mac_add));
	cJSON_AddItemToObject(cjson_param,"status_led",cJSON_CreateNumber(status_led));
	cJSON_AddItemToObject(cjson_param,"storage_total",cJSON_CreateNumber(storage.total));
	cJSON_AddItemToObject(cjson_param,"storage_remain",cJSON_CreateNumber(storage.remain));
	cJSON_AddItemToObject(cjson_param,"status_camera",cJSON_CreateNumber(status_camera));
	cJSON_AddItemToObject(cjson_param,"motion_monitor",cJSON_CreateNumber(motion_monitor));
	cJSON_AddItemToObject(cjson_param,"cloud_store",cJSON_CreateNumber(cloud_store));
	cJSON_AddItemToObject(cjson_param,"motion_monitor_sensitivity",cJSON_CreateNumber(motion_monitor_sens));
    }
    
    param = (int8_t *)cJSON_PrintUnformatted(cjson_param);
    iotgoWriteUpdateToServer(param);
    if(param)
    {
	pFree(param);
    }
    if(cjson_param)
    {
	cJSON_Delete(cjson_param);
    }
}

int8_t iotgoGetUserApiKey(uint8_t *user_apikey)
{
    iotgoReadUserApiKey(user_apikey);
    return 0;
}
